package nuist.hanniko.stu.webbackend.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import nuist.hanniko.stu.webbackend.model.User;
import nuist.hanniko.stu.webbackend.model.UserRole;
import org.apache.commons.net.util.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;

public class TokenHelper {

    private static final long TOKEN_EXPIRED_TIME = 7 * 24 * 60 * 60 * 1000;

    private static final String SALT = "APieceOfSalt";

    public static String generateToken(String uid, UserRole... roles) {
        Map<String, Object> map = new HashMap<>();
        List<String> roleList = new ArrayList<>();

        for (UserRole role : roles) {
            roleList.add(role.name());
        }

        map.put("uid", uid);
        map.put("role", roleList);
        return createJwT(map, TOKEN_EXPIRED_TIME);
    }

    public static String generateToken(String uid, String... roles) {
        List<UserRole> roleList = new ArrayList<>();

        for (String role : roles) {
            roleList.add(UserRole.valueOf(role));
        }

        return generateToken(uid, roleList.toArray(new UserRole[roleList.size()]));
    }

    public static Claims extractJwt(String token) {
        SecretKey key = getSecretKey();
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token).getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    private static String createJwT(Map<String, Object> claims, Long time) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        Date now = new Date(System.currentTimeMillis());

        SecretKey secretKey = getSecretKey();
        JwtBuilder builder = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(now)
                .signWith(signatureAlgorithm, secretKey);

        if (time > 0) {
            long expMillis = now.getTime() + time;
            Date expireDate = new Date(expMillis);
            builder.setExpiration(expireDate);
        }

        return builder.compact();
    }

    private static SecretKey getSecretKey() {
        byte[] encodeKey = Base64.decodeBase64(SALT);
        return new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES");
    }
}
